package com.ysstech.common.util.imgutil;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.ImageProducer;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ImageIOHelper {
    private static final Logger log = LoggerFactory.getLogger(ImageIOHelper.class);

    public static Collection<File> createImage(File imageFile, File tempFile,
                                               String imageFormat, int rows, int cols) throws Exception {
        ArrayList<File> files = new ArrayList<File>();
        ImageInputStream iis = null;
        ImageReader reader = null;
        try {
            tempFile.mkdirs();

            Iterator<ImageReader> readers = ImageIO
                    .getImageReadersByFormatName(imageFormat);
            reader = readers.next();
            iis = ImageIO.createImageInputStream(imageFile);
            reader.setInput(iis);
            BufferedImage bi = reader.read(0);

            File oriImageFile = new File(tempFile, imageFile.getName());
            writeImage(oriImageFile, bi, imageFormat);
            files.add(oriImageFile);

            BufferedImage bo = bi;
            // 直接纵横切割
            files.addAll(cutImage(imageFile, tempFile, bo, imageFormat, 0, rows));
            files.addAll(cutImage(imageFile, tempFile, bo, imageFormat, 1, cols));

            ImageFilter filter = new ImageFilter(bi);
            bo = filter.changeGrey();
            // 灰度图后，根据黑白色块切割，只能提高文字在大段空白处的辨识率
            files.addAll(cutImageByBinary(imageFile, tempFile, bo, imageFormat,
                    0));
            files.addAll(cutImageByBinary(imageFile, tempFile, bo, imageFormat,
                    1));
        } catch (Exception e) {
            log.error("创建图片出错：", e);
            throw new Exception(e);
        } finally {
            if (iis != null) {
                iis.close();
            }
            if (reader != null) {
                reader.dispose();
            }
        }
        return files;
    }

    public static void writeImage(File file, BufferedImage bi,
                                  String imageFormat) throws IOException {
        ImageIO.write(bi, imageFormat, file);
    }

    /**
     * 切割图片
     *
     * @param file
     * @param bi
     * @param type  0——横切；1——纵切
     * @param count
     * @return
     * @throws IOException
     */
    public static Collection<File> cutImage(File file, File tempFile,
                                            BufferedImage bi, String imageFormat, int type, int count)
            throws IOException {
        int x = 0;
        int y = 0;
        int width = type == 0 ? bi.getWidth() : bi.getWidth() / count;
        int height = type == 0 ? bi.getHeight() / count : bi.getHeight();
        ArrayList<File> files = new ArrayList<File>();
        for (int i = 0; i < count; i++) {
            BufferedImage bo = bi.getSubimage(x, y, width, height);
            if (type == 0) {
                y += height;
            } else {
                x += width;
            }

            File t = new File(tempFile, file.getName() + "_" + type + "_" + i);
            writeImage(t, bo, imageFormat);

            files.add(t);
        }
        return files;
    }

    /**
     * 通过图片二值化切割
     *
     * @param file
     * @param bi
     * @param type 0——横切；1——纵切
     * @return
     * @throws Exception
     */
    public static Collection<File> cutImageByBinary(File file, File tempFile,
                                                    BufferedImage bi, String imageFormat, int type) throws Exception {
        int x = 0;
        int y = 0;
        int width = 0;
        int height = 0;
        ArrayList<File> files = new ArrayList<File>();
        ImageFilter filter = new ImageFilter(bi);
        filter.initBinaryArray();
        for (; x < bi.getWidth() && y < bi.getHeight(); ) {
            if (type == 0) {
                y = filter.getNextHeight(y, 0);
                height = filter.getNextHeight(y, 1) - y;
                x = filter.getNextWidth(0, 0, y, y + height);
                width = filter.getNextWidth(x, 1, y, y + height) - x;
            } else {
                x = filter.getNextWidth(x, 0);
                width = filter.getNextWidth(x, 1) - x;
                y = filter.getNextHeight(0, 0, x, x + width);
                height = filter.getNextHeight(y, 1, x, x + width) - y;
            }
            if (x + width > bi.getWidth() || y + height > bi.getHeight()) {
                break;
            }
            if (x + width == bi.getWidth() && y + height == bi.getHeight()) {
                break;
            }
            BufferedImage bo = bi.getSubimage(x, y, width, height);

            File t = new File(tempFile, file.getName() + "_" + type + "_" + x
                    + "_" + y + "_" + width + "_" + height);
            writeImage(t, bo, imageFormat);

            if (type == 0) {
                y += height;
            } else {
                x += width;
            }

            files.add(t);
        }
        return files;
    }

    public static BufferedImage imageToBufferedImage(Image image) throws Exception {
        BufferedImage bufferedImage = new BufferedImage(image.getWidth(null),
                image.getHeight(null), BufferedImage.TYPE_INT_RGB);
        Graphics2D g = bufferedImage.createGraphics();
        g.drawImage(image, 0, 0, null);
        return bufferedImage;
    }

    public static BufferedImage imageProducerToBufferedImage(
            ImageProducer imageProducer) throws Exception {
        return imageToBufferedImage(Toolkit.getDefaultToolkit().createImage(
                imageProducer));
    }

    public static byte[] image_byte_data(BufferedImage image) throws Exception {
        WritableRaster raster = image.getRaster();
        DataBufferByte buffer = (DataBufferByte) raster.getDataBuffer();
        return buffer.getData();
    }

    public static String getFormatName(Object o) throws Exception {
        ImageInputStream iis = null;
        ImageReader reader = null;
        try {
            iis = ImageIO.createImageInputStream(o);

            Iterator<ImageReader> iter = ImageIO.getImageReaders(iis);
            if (!iter.hasNext()) {
                return null;
            }

            reader = iter.next();

            return reader.getFormatName();
        } catch (IOException e) {
            log.error("创建图片出错：", e);
            throw new Exception(e);
        } finally {
            if (reader != null) {
                reader.dispose();
            }
            if (iis != null) {
                iis.close();
            }
        }
    }

    public static Collection<SubImage> getSubImage(File input, int row, int col) throws Exception {
        try {
            BufferedImage bi = getBufferedImage(input);

            int width = bi.getWidth();
            int height = bi.getHeight();
            // 列宽
            int colWidth = width / col;
            // 行高
            int rowHeight = height / row;
            // x坐标
            int x = 0;
            // y坐标
            int y = 0;

            List<SubImage> sis = new ArrayList<SubImage>();
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) {
                    SubImage si = new SubImage();
                    si.setX(x);
                    si.setY(y);
                    si.setWidth(colWidth);
                    si.setHeight(rowHeight);
                    log.info("image " + i + "," + j + " " + x + "," + y + ","
                            + colWidth + "," + rowHeight);

                    BufferedImage bo = bi
                            .getSubimage(x, y, colWidth, rowHeight);
                    si.setBufferedImage(bo);

                    sis.add(si);

                    x += colWidth;
                }
                x = 0;
                y += rowHeight;
            }

            return sis;
        } catch (Exception e) {
            log.error("判断图片出错"+e.getMessage(), e);
            throw new Exception(e);
        }
    }

    public static BufferedImage getBufferedImage(File input) throws Exception {
        BufferedImage bi = null;
        try {
            Image image = Toolkit.getDefaultToolkit().getImage(
                    input.getAbsolutePath());

            return toBufferedImage(image);
        } catch (Exception e) {
            log.error("判断图片出错"+e.getMessage(), e);
            throw new Exception(e);
        }
    }

    public static BufferedImage toBufferedImage(Image image) throws Exception {
        if (image instanceof BufferedImage) {
            return (BufferedImage) image;
        }
        // This code ensures that all the pixels in the image are loaded
        image = new ImageIcon(image).getImage();
        // Determine if the image has transparent pixels; for this method's
        // implementation, see e661 Determining If an Image Has Transparent
        // Pixels
        // boolean hasAlpha = hasAlpha(image);
        // Create a buffered image with a format that's compatible with the
        // screen
        BufferedImage bimage = null;

        GraphicsEnvironment ge = GraphicsEnvironment
                .getLocalGraphicsEnvironment();

        try {
            // Determine the type of transparency of the new buffered image
            int transparency = Transparency.OPAQUE;
            /*
             * if (hasAlpha) {
			 * 
			 * transparency = Transparency.BITMASK;
			 * 
			 * }
			 */
            // Create the buffered image
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(image.getWidth(null),
                    image.getHeight(null), transparency);
        } catch (HeadlessException e) {
            log.error("判断图片出错"+e.getMessage(), e);
            throw new Exception(e);
            // The business does not have a screen
        }

        if (bimage == null) {
            // Create a buffered image using the default color model
            int type = BufferedImage.TYPE_INT_RGB;
            // int type = BufferedImage.TYPE_3BYTE_BGR;//by wang
            /*
             * if (hasAlpha) {
			 * 
			 * type = BufferedImage.TYPE_INT_ARGB;
			 * 
			 * }
			 */
            bimage = new BufferedImage(image.getWidth(null),
                    image.getHeight(null), type);
        }

        // Copy image to buffered image
        Graphics g = bimage.createGraphics();
        // Paint the image onto the buffered image
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return bimage;
    }
}
